libobs_wrapper\display\window_manager/
position_trait.rs1use windows::Win32::{
2 Foundation::HWND,
3 Graphics::Gdi::{RedrawWindow, RDW_ERASE, RDW_INVALIDATE},
4 UI::WindowsAndMessaging::{
5 SetWindowPos, HWND_BOTTOM, SWP_NOACTIVATE, SWP_NOCOPYBITS, SWP_NOSIZE, SWP_NOZORDER,
6 SWP_SHOWWINDOW,
7 },
8};
9
10use crate::{display::ObsDisplayRef, run_with_obs, rw_lock_blocking_read};
11
12#[cfg_attr(not(feature = "blocking"), async_trait::async_trait)]
13pub trait WindowPositionTrait {
14 #[cfg_attr(feature = "blocking", remove_async_await::remove_async_await)]
15 async fn set_render_at_bottom(&self, render_at_bottom: bool);
16 #[cfg_attr(feature = "blocking", remove_async_await::remove_async_await)]
17 async fn get_render_at_bottom(&self) -> bool;
18 #[cfg_attr(feature = "blocking", remove_async_await::remove_async_await)]
19 async fn set_pos(&self, x: i32, y: i32) -> windows::core::Result<()>;
20 #[cfg_attr(feature = "blocking", remove_async_await::remove_async_await)]
21 async fn set_size(&self, width: u32, height: u32) -> anyhow::Result<()>;
22 #[cfg_attr(feature = "blocking", remove_async_await::remove_async_await)]
23 async fn set_scale(&self, scale: f32);
24
25 #[cfg_attr(feature = "blocking", remove_async_await::remove_async_await)]
26 async fn get_pos(&self) -> (i32, i32);
27 fn get_pos_blocking(&self) -> (i32, i32);
28
29 #[cfg_attr(feature = "blocking", remove_async_await::remove_async_await)]
30 async fn get_size(&self) -> (u32, u32);
31 fn get_size_blocking(&self) -> (u32, u32);
32
33 #[cfg_attr(feature = "blocking", remove_async_await::remove_async_await)]
34 async fn get_scale(&self) -> f32;
35}
36
37#[cfg_attr(not(feature = "blocking"), async_trait::async_trait)]
38impl WindowPositionTrait for ObsDisplayRef {
39 #[cfg_attr(feature = "blocking", remove_async_await::remove_async_await)]
40 async fn set_render_at_bottom(&self, render_at_bottom: bool) {
41 log::trace!("Set render bottom");
42 self.manager.write().await.render_at_bottom = render_at_bottom;
43 }
44
45 #[cfg_attr(feature = "blocking", remove_async_await::remove_async_await)]
46 async fn get_render_at_bottom(&self) -> bool {
47 self.manager.read().await.render_at_bottom
48 }
49
50 #[cfg_attr(feature = "blocking", remove_async_await::remove_async_await)]
51 async fn set_pos(&self, x: i32, y: i32) -> windows::core::Result<()> {
52 log::trace!("Set pos {x} {y}");
53 let mut m = self.manager.write().await;
54
55 assert!(
56 m.obs_display.is_some(),
57 "Invalid state. The display should have been created and set, but it wasn't."
58 );
59
60 let insert_after = if m.render_at_bottom {
61 HWND_BOTTOM
62 } else {
63 HWND::default()
64 };
65
66 m.x = x;
67 m.y = y;
68
69 unsafe {
70 let flags = SWP_NOCOPYBITS | SWP_NOSIZE | SWP_NOACTIVATE;
71 SetWindowPos(
73 m.hwnd.0,
74 Some(insert_after),
75 x,
76 y,
77 1 as i32,
78 1 as i32,
79 flags,
80 )?;
81 }
82
83 Ok(())
84 }
85
86 #[cfg_attr(feature = "blocking", remove_async_await::remove_async_await)]
87 async fn get_pos(&self) -> (i32, i32) {
88 let m = self.manager.read().await;
89 (m.x, m.y)
90 }
91 #[cfg_attr(feature = "blocking", remove_async_await::remove_async_await)]
92 fn get_pos_blocking(&self) -> (i32, i32) {
93 let m = rw_lock_blocking_read!(self.manager);
94 (m.x, m.y)
95 }
96
97 #[cfg_attr(feature = "blocking", remove_async_await::remove_async_await)]
98 async fn get_size(&self) -> (u32, u32) {
99 let m = self.manager.read().await;
100 (m.width, m.height)
101 }
102
103 fn get_size_blocking(&self) -> (u32, u32) {
104 let m = rw_lock_blocking_read!(self.manager);
105 (m.width, m.height)
106 }
107
108 #[cfg_attr(feature = "blocking", remove_async_await::remove_async_await)]
109 async fn set_size(&self, width: u32, height: u32) -> anyhow::Result<()> {
110 log::trace!("Set size {width} {height}");
111 let mut m = self.manager.write().await;
112 assert!(
113 m.obs_display.is_some(),
114 "Invalid state. The display should have been created and set, but it wasn't."
115 );
116
117 m.width = width;
118 m.height = height;
119
120 let pointer = m.obs_display.as_ref().unwrap().clone();
121 unsafe {
122 SetWindowPos(
123 m.hwnd.0,
124 None,
125 m.x,
126 m.y,
127 width as i32,
128 height as i32,
129 SWP_NOCOPYBITS | SWP_NOACTIVATE | SWP_NOZORDER | SWP_SHOWWINDOW,
130 )?;
131
132 let _ = RedrawWindow(Some(m.hwnd.0), None, None, RDW_ERASE | RDW_INVALIDATE);
133 }
134
135 run_with_obs!(self.runtime, (pointer), move || unsafe {
136 libobs::obs_display_resize(pointer, width, height);
137 }).await?;
138 Ok(())
139 }
140
141 #[cfg_attr(feature = "blocking", remove_async_await::remove_async_await)]
142 async fn set_scale(&self, scale: f32) {
143 log::trace!("Set scale {scale}");
144 self.manager.write().await.scale = scale;
145 }
146
147 #[cfg_attr(feature = "blocking", remove_async_await::remove_async_await)]
148 async fn get_scale(&self) -> f32 {
149 self.manager.read().await.scale
150 }
151}